(function () {
    if (window.JSBridge) {
        return;
    }
    let uniqueId = 1;
    const PROTOCOL = "nstc://";
    const SCHEMA_NATIVE_FETCH_CALL = PROTOCOL + "_native_fetch_call/";
    const SCHEMA_NATIVE_FETCH_CALL_RETURN = PROTOCOL + "_native_fetch_call_return/";
    const messageQueue4Native = [];
    const messageCallBacks4Native = {};
    const handlers4Native = {};

    function registerHandler(handlerName, func) {
        handlers4Native[handlerName] = func
    }

    function callNative(handlerName, data, callback) {
        const callbackId = uniqueId++;
        if (!data) {
            data = {}
        }
        const message = handlerName + "/" + callbackId + "/" + (typeof data === 'string' ? data : JSON.stringify(data));
        messageQueue4Native.push(message);
        if (callback) {
            messageCallBacks4Native[callbackId] = callback;
        }
        didPolicy(SCHEMA_NATIVE_FETCH_CALL);
    }

    function didPolicy(src) {
        let iframe = document.createElement('iframe');
        iframe.setAttribute("src", src);
        iframe.setAttribute("style", "display:none;");
        iframe.setAttribute("height", "0px");
        iframe.setAttribute("width", "0px");
        iframe.setAttribute("frameborder", "0");
        document.body.appendChild(iframe);
        iframe.parentNode.removeChild(iframe);
        iframe = null;
    }

    function _native_fetch_call() {
        let message = messageQueue4Native.pop();
        do {
            if (message) {
                didPolicy(SCHEMA_NATIVE_FETCH_CALL_RETURN + message);
            }
            message = messageQueue4Native.pop();
        } while (message)

    }

    function _native_call_return(callbackId, data) {
        const callback = messageCallBacks4Native[callbackId];
        if (callback) {
            callback(data);
            delete messageCallBacks4Native[callbackId];
        }
    }

    function _native_call_web(handlerName, data) {
        if (handlers4Native[handlerName]) {
            handlers4Native[handlerName](data);
        }
    }

    const JSBridge = window.JSBridge = {
        callNative,
        registerHandler,
        _native_fetch_call,
        _native_call_return,
        _native_call_web
    };

    const JSBridgeEvents = document.createEvent("Events");
    JSBridgeEvents.initEvent("JSBridgeReadyEvent");
    JSBridgeEvents.JSBridge = JSBridge;
    document.dispatchEvent(JSBridgeEvents);
})();
